﻿/**
 * это отдельный проект, я его написал вчера (10.03.08), чтобы показать тебе как я представляю
 * себе взаимодействие нашего кода. Обрати внимание на TODO и сложности в реализации 
 * DragAndDrop'a, который так доконца и не удалось реализовать
 * Проект запускается, требует только одно bmp (путь должен быть верным)
 * Предполагается потом вырезать из этого проекта классы Vertex, SimpleVertex и вставить 
 * в основной проект. Посмотри реализацию Form, я себе так представляю твою часть кода.
 * */

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Drawing.Drawing2D;

namespace WindowsApplication1
{
    public partial class Form1 : Form
    {
        List<Element> elems = new List<Element>();

        public Form1()
        {
            elems.Add(new Vertex(10, 60));
            elems.Add(new Vertex(10, 210));
            elems.Add(new SimpleVertex(200, 610));
            InitializeComponent();
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            foreach (Element el in elems)
                el.OnPaint(sender, e);
        }

        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
            {
                if(el_selected!=null)
                {
                    Element el = MatchElement(e.Location);
                    if ((el != null) && (el != el_selected))
                    {
                        el.DragDrop(this,new GrapherDragEventArgs(e.Location,el_selected));
                        Invalidate();
                    }
                }
            }
        }

        Element el_selected;
        private void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            el_selected = MatchElement(e.Location);
        }
        private Element MatchElement(Point p)
        {
            Element match=null;
            foreach (Element el in elems)
                if (RectangleHelper.ContainPoint(el.GetBorder(), p)) match = el;
            return match;
        }
    }

    class GrapherDragEventArgs
    {
        public GrapherDragEventArgs(Point location,Element data)
        {
            this.data=data;
            this.location=location;
        }

        public Point location;
        public Element data;
    }

    abstract class Element
    {
        public abstract void OnPaint(object sender, PaintEventArgs e);
        public abstract void DragDrop(object sender, GrapherDragEventArgs e);

        public abstract Rectangle GetBorder();
        public abstract Element GetDragDropData();
        //TODO:
        //public abstract IDataObject GetDragDropData();
        //TODO:
        //public abstract void DragDrop(object sender, DragEventArgs e);
    }

    class SimpleVertex : Element
    {
        int x; int y;
        public SimpleVertex(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
        //Bitmap bmp = new Bitmap("C:\\bmp.bmp");
        Bitmap bmp = new Bitmap(@"..\..\..\..\..\ctem.gui\ctem.gui\bin\Debug\Resource\images\AlgebraicElement\accumulator.bmp");
        public override void OnPaint(object sender, PaintEventArgs e)
        {
            e.Graphics.DrawImage(bmp, new Rectangle(x, y, 100, 100));
        }
        public override Rectangle GetBorder()
        {
            return new Rectangle(x, y, bmp.Width, bmp.Height);
        }
        public override void DragDrop(object sender, GrapherDragEventArgs e) { }
        public override Element GetDragDropData()
        {
            return this;
        }
    }

    class Vertex : Element
    {
        public class Cell
        {
            public Cell(int x, int y, int width, int height, Element el)
            {
                body = new Rectangle(x, y, width, height);
                content = el;
            }
            public Cell(Element el)
            {
                content = el;
            }
            public Element content;
            //клетка
            public Rectangle body;
            //окружение клетки
            public Rectangle cellsurround;

            public void OnPaint(object sender, PaintEventArgs e)
            {
                Graphics g = e.Graphics;
                
                g.FillRectangle(SystemBrushes.ScrollBar, cellsurround);

                if (content == null)
                    g.FillRectangle(SystemBrushes.Info, body);
                else
                    content.OnPaint(sender, e);
            }
        }

        public Vertex(int x,int y)
        {
            this.x = x;
            this.y = y;
            cells.Add(new Cell(null));
            cells.Add(new Cell(null));
            cells.Add(new Cell(null));
            cells.Add(new Cell(null));
            cells.Add(new Cell(null));
            
            RecalculateGeometry();
        }

        //public readonly properties
        public Rectangle border;
        List<Cell> cells = new List<Cell>();

        #region Fields
        //Композитная вершина, принимает размеры соответсвенно 
        //размерами и числу вложенных кленток. Каждая клетка
        //положена на фон.

        //координаты верхнего левого угла вершины
        int x=10;
        int y=50;

        //габариты композитной вершины целиком
        int border_w;
        int border_h;

        //расстояние между границей вершины и окружением клетки
        int border_surr_gap_w =4;
        int border_surr_gap_h = 4;

        //расстояние между окружением клетки и её границей
        int surr_cell_gap_w  =2;
        int surr_cell_gap_h = 2;
        
        //расстояние между клетками
        int cell_cell_gap=6;
        
        //габариты клетки
        int cell_w = 85;
        int cell_h = 70;
#endregion

        private void RecalculateGeometry()
        {
            int celln = cells.Count;

            //рамка
            border_h = cell_h + 2*(border_surr_gap_h + surr_cell_gap_h);
            border_w = celln * cell_w + (celln - 1) * cell_cell_gap + 2 * (surr_cell_gap_w + border_surr_gap_w);
            border = new Rectangle(x, y, border_w, border_h);

            //окружение клетки
            int cellsurround_x = x + border_surr_gap_w;
            int cellsurround_y = y + border_surr_gap_h;

            //клетка
            int cell_x = cellsurround_x + surr_cell_gap_w;
            int cell_y = cellsurround_y + surr_cell_gap_h;

            Rectangle temp_cellsurround = new Rectangle(cellsurround_x, cellsurround_y, cell_w + surr_cell_gap_w * 2, cell_h + surr_cell_gap_h * 2); ;
            Rectangle temp_cell = new Rectangle(cell_x, cell_y, cell_w, cell_h); ;

            foreach (Cell c in cells)
            {
                c.cellsurround = temp_cellsurround;
                cellsurround_x = cellsurround_x + cell_cell_gap + cell_w;
                temp_cellsurround = RectangleHelper.Move(c.cellsurround, new Point(cellsurround_x, cellsurround_y));

                c.body = temp_cell;
                cell_x = cell_x + cell_cell_gap + cell_w;
                temp_cell = RectangleHelper.Move(c.body, new Point(cell_x, cell_y));
            }
         
        }

        public override void OnPaint(object sender, PaintEventArgs e)
        {
            RecalculateGeometry();

            Graphics g = e.Graphics;

            Rectangle border = new Rectangle(x, y, border_w, border_h);
            g.FillRectangle(SystemBrushes.ButtonShadow, border);

            foreach (Cell c in cells)
            {
                c.OnPaint(sender, e);
            }
            
        }

        public override Rectangle GetBorder()
        {
            return new Rectangle(border.Location, border.Size);
        }

        public override void DragDrop(object sender, GrapherDragEventArgs e)
        {
            Cell match=null;
            foreach (Cell c in cells)
                if (RectangleHelper.ContainPoint(c.body, e.location)) match = c;

            if (match!=null)
            {
                match.content = e.data;
            }
        }

        public override Element GetDragDropData()
        {
            return this;
        }
    }

    

    static class RectangleHelper
    {
        public static bool ContainPoint(Rectangle Rect, Point p)
        {
            return ((Rect.Left <= p.X) && (Rect.Right >= p.X) && (Rect.Top <= p.Y) && (Rect.Bottom >= p.Y));
        }
        public static Rectangle Move(Rectangle Rect, Point newLeftTop)
        {
            Rectangle newrect = new Rectangle(Rect.Location, Rect.Size);
            newrect.Location = newLeftTop;
            return newrect;
        }
    }


}